import { OhosPluginId, OhosAppContext } from '@ohos/hvigor-ohos-plugin'
import { hvigor, HvigorNode, FileUtil } from '@ohos/hvigor'
import * as fs from 'fs'
import * as path from 'path'


/**
 * caseAdd 任务实现
 * 根据caseNO生成对应的编译配置文件并添加到构建配置中
 * @param node - Hvigor节点对象
 */
export function caseAdd(node: HvigorNode) {
  const caseNO = hvigor.getParameter().getExtParam('caseNO');
  addCaseByNO(caseNO, node);
}

/**
 * caseAddAll 任务实现
 * 遍历所有的caseNO生成对应的编译配置文件并添加到构建配置中
 * @param node - Hvigor节点对象
 */
export function caseAddAll(node: HvigorNode) {
  const appContext: OhosAppContext = node.getContext(OhosPluginId.OHOS_APP_PLUGIN);
  const projectPath = appContext.getProjectPath();
  const caseDirRootPath = FileUtil.pathResolve(projectPath, 'cases');

  // 递归查找所有的case模块
  function addAllCaseConfig(dir: string): string | null {
    let files = fs.readdirSync(dir, { withFileTypes: true })
    for (let file of files) {
      const filePath = FileUtil.pathResolve(dir, file.name);
      if (file.isDirectory()) {
        if (file.name.startsWith('case')) {
          const moduleName = file.name;
          const moduleRelativePath = path.relative(projectPath, filePath).replace(/\\/g, '/');
          addCaseConfig(projectPath, { name: moduleName, relativePath: moduleRelativePath });
        } else {
          addAllCaseConfig(filePath);
        }
      }
    }
  }

  addAllCaseConfig(caseDirRootPath);
}

/**
 * caseClear 任务实现
 * 清理所有case相关配置
 */
export function caseClear(node: HvigorNode) {
  const appContext: OhosAppContext = node.getContext(OhosPluginId.OHOS_APP_PLUGIN)
  const projectPath = appContext.getProjectPath()
  const buildJsonPath = path.join(projectPath, 'case.build.json')
  const buildProfilePath = path.join(projectPath, 'build-profile.json5')
  const defaultPackagePath = path.join(projectPath, 'products/default/oh-package.json5')

  // 清理 case.build.json
  if (FileUtil.exist(buildJsonPath)) {
    fs.unlinkSync(buildJsonPath)
    console.log('Cleared case build configuration')
  }

  // 还原 build-profile.json5
  if (FileUtil.exist(buildProfilePath)) {
    const buildProfile = FileUtil.readJson5(buildProfilePath)
    // 只保留非case模块
    buildProfile.modules = buildProfile.modules.filter(
      module => !module.srcPath.startsWith('./cases/')
    )
    FileUtil.writeFileSync(buildProfilePath, JSON.stringify(buildProfile, null, 2))
    console.log('Restored build-profile.json5')
  }

  // 还原 default 模块依赖
  if (FileUtil.exist(defaultPackagePath)) {
    const defaultPackage = FileUtil.readJson5(defaultPackagePath)
    // 移除所有case模块的依赖
    if (defaultPackage.dependencies) {
      Object.keys(defaultPackage.dependencies).forEach(key => {
        if (key.startsWith('case')) {
          delete defaultPackage.dependencies[key]
        }
      })
      FileUtil.writeFileSync(defaultPackagePath, JSON.stringify(defaultPackage, null, 2))
      console.log('Restored default module dependencies')
    }
  }
}

/**
 * generateModule 任务实现
 * 创建新模块
 * @param node
 */
export function generateModule(node: HvigorNode) {
  const appContext: OhosAppContext = node.getContext(OhosPluginId.OHOS_APP_PLUGIN)
  const projectPath = appContext.getProjectPath();

  const demoname = hvigor.getParameter().getExtParam('demoname')
  if (!demoname) {
    throw new Error('Parameter demoname is required')
  }

  let params = demoname.split('-');
  if (params.length < 2) {
    throw new Error('Parameter' + demoname + 'is invalid')
  }

  const typeName = params[0];
  const typePath = FileUtil.pathResolve(projectPath, 'cases', typeName);
  if (!fs.existsSync(typePath)) {
    throw new Error(typeName + 'not found')
  }

  const caseNO = params[1];
  let desc = '';
  if (params.length > 2) {
    desc = params[2];
  }

  const modulePath = FileUtil.pathResolve(projectPath, 'cases', typeName, caseNO);
  const templatePath = FileUtil.pathResolve(projectPath, 'common', 'framework', 'template', 'moduleTemplate');

  // 校验case编号重复
  if (fs.existsSync(modulePath)) {
    throw new Error(modulePath + ' exists')
  }

  // 创建模块
  fs.mkdirSync(modulePath);
  copyFiles(templatePath, modulePath);

  // 修改文件
  // 修改oh-package.json5文件
  modifyOhPackage(caseNO, modulePath);
  // 修改manifest.json文件
  modifyManifest(caseNO, desc, modulePath);
  // 修改module.json5文件
  modifyModuleJson5(caseNO, modulePath);
  // 修改MainPage.ets文件
  modifyMainPage(caseNO, modulePath);

  addCaseByNO(caseNO, node);
}

function addCaseByNO(caseNO, node) {
  if (!caseNO) {
    throw new Error('Parameter caseNO is required')
  }

  const appContext: OhosAppContext = node.getContext(OhosPluginId.OHOS_APP_PLUGIN)
  const projectPath = appContext.getProjectPath()

  // 查找匹配的模块
  const casesDir = FileUtil.pathResolve(projectPath, 'cases')
  if (!FileUtil.exist(casesDir)) {
    throw new Error(`cases directory not found at: ${casesDir}`)
  }

  // 递归查找匹配的模块
  function findModuleInDir(dir: string): string | null {
    const items = fs.readdirSync(dir)
    for (const item of items) {
      const itemPath = FileUtil.pathResolve(dir, item)
      const stat = fs.statSync(itemPath)

      if (stat.isDirectory()) {
        if (item.includes(caseNO)) {
          return itemPath
        }
        const result = findModuleInDir(itemPath)
        if (result) {
          return result
        }
      }
    }
    return null
  }

  const modulePath = findModuleInDir(casesDir)
  if (!modulePath) {
    throw new Error(`No matching module found for case ID: ${caseNO}`)
  }

  const moduleName = path.basename(modulePath)
  const moduleRelativePath = path.relative(projectPath, modulePath).replace(/\\/g, '/');

  addCaseConfig(projectPath, { name: moduleName, relativePath: moduleRelativePath });
}

interface caseModuleData {
  name: string
  relativePath: string
}

/**
 * 模块配置接口定义
 */
interface ModuleConfig {
  name: string // 模块名称
  srcPath: string // 模块源码路径
  [key: string]: string // 添加索引签名
}

function addCaseConfig(projectPath: string, caseModuleData: caseModuleData) {
  const buildJsonPath = FileUtil.pathResolve(projectPath, 'case.build.json')
  const buildProfilePath = FileUtil.pathResolve(projectPath, 'build-profile.json5')

  // 读取现有配置或创建新配置
  let buildConfig = {
    modules: [] as ModuleConfig[]
  }

  // 如果存在配置文件，读取现有配置
  if (FileUtil.exist(buildJsonPath)) {
    buildConfig = FileUtil.readJson5(buildJsonPath)
  }

  // 读取 build-profile.json5
  const buildProfile = FileUtil.exist(buildProfilePath)
    ? FileUtil.readJson5(buildProfilePath)
    : { modules: [] }

  // 检查模块是否已存在，如果不存在则添加
  if (!buildConfig.modules.some(m => m.name === caseModuleData.name)) {
    buildConfig.modules.push({
      name: caseModuleData.name,
      srcPath: `./${caseModuleData.relativePath}`
    })
  }

  // 更新 build-profile.json5，添加新模块
  buildConfig.modules.forEach(module => {
    if (!buildProfile.modules.some(m => m.name === module.name)) {
      buildProfile.modules.push({
        name: module.name,
        srcPath: module.srcPath
      })
    }
  })
  FileUtil.writeFileSync(buildProfilePath, JSON.stringify(buildProfile, null, 2))

  // 更新 default 模块的依赖
  const defaultPackagePath = FileUtil.pathResolve(projectPath, 'products/default/oh-package.json5')
  let defaultPackage = FileUtil.exist(defaultPackagePath)
    ? FileUtil.readJson5(defaultPackagePath)
    : { dependencies: {} }

  // 确保所有模块的依赖都存在
  buildConfig.modules.forEach(module => {
    const relativePath = path.relative(
      path.join(projectPath, 'products/default'),
      path.join(projectPath, module.srcPath)
    )
    defaultPackage.dependencies[module.name.toLowerCase()] = `file:${relativePath}`
  })

  FileUtil.writeFileSync(defaultPackagePath, JSON.stringify(defaultPackage, null, 2))

  // 保存 case.build.json
  FileUtil.ensureFileSync(buildJsonPath)
  FileUtil.writeFileSync(buildJsonPath, JSON.stringify(buildConfig, null, 2))
}

function copyFiles(from, to) {
  let files = fs.readdirSync(from, { withFileTypes: true });
  for (let file of files) {
    const fromFilePath = FileUtil.pathResolve(from, file.name);
    const toFilePath = FileUtil.pathResolve(to, file.name);
    if (!file.isDirectory()) {
      fs.copyFileSync(fromFilePath, toFilePath);
    } else {
      fs.mkdirSync(toFilePath);
      copyFiles(fromFilePath, toFilePath);
    }
  }
}

function modifyOhPackage(caseNO, modulePath) {
  const oh_package_path = FileUtil.pathResolve(modulePath, 'oh-package.json5');
  const oh_package_content = FileUtil.readFileSync(oh_package_path).toString();
  const result = oh_package_content.replace('caseNO', caseNO);
  FileUtil.writeFileSync(oh_package_path, result);
}

function modifyManifest(caseNO, desc, modulePath) {
  const manifest_path = FileUtil.pathResolve(modulePath, 'manifest.json');
  const manifest_content = FileUtil.readFileSync(manifest_path).toString();
  const data = {
    "caseNO": caseNO,
    "desc": desc,
    "home": caseNO + "/home",
    "dependencies": []
  }
  const result = manifest_content.replace(/\${(.*?)}/g, (match, key) => data[key]);
  FileUtil.writeFileSync(manifest_path, result);
}

function modifyModuleJson5(caseNO, modulePath) {
  const module_json5_path = FileUtil.pathResolve(modulePath, 'src', 'main', 'module.json5');
  const module_json5_content = FileUtil.readFileSync(module_json5_path).toString();
  const result = module_json5_content.replace('caseNO', caseNO);
  FileUtil.writeFileSync(module_json5_path, result);
}

function modifyMainPage(caseNO, modulePath) {
  const mainPage_path = FileUtil.pathResolve(modulePath, 'src', 'main', 'ets', 'components', 'MainPage.ets');
  const mainPage_content = FileUtil.readFileSync(mainPage_path).toString();
  const result = mainPage_content.replace('${caseNO}', caseNO);
  FileUtil.writeFileSync(mainPage_path, result);
}
